/******************************************************************************* * Copyright (c) 2005, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.ui.internal.commands; import java.util.ArrayList; import java.util.List; import org.eclipse.core.commands.AbstractParameterValueConverter; import org.eclipse.core.commands.Category; import org.eclipse.core.commands.Command; import org.eclipse.core.commands.ParameterType; import org.eclipse.core.commands.State; import org.eclipse.core.commands.common.HandleObject; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionDelta; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.IRegistryChangeEvent; import org.eclipse.core.runtime.Platform; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.commands.ICommandService; import org.eclipse.ui.internal.WorkbenchMessages; import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants; import org.eclipse.ui.internal.services.RegistryPersistence; import org.eclipse.ui.internal.util.PrefUtil; /** * <p> * A static class for accessing the registry and the preference store. * </p> */ public final class CommandPersistence extends RegistryPersistence { /** * The index of the category elements in the indexed array. * * @see CommandPersistence#read() */ private static final int INDEX_CATEGORY_DEFINITIONS = 0; /** * The index of the command elements in the indexed array. * * @see CommandPersistence#read() */ private static final int INDEX_COMMAND_DEFINITIONS = 1; /** * The index of the commandParameterType elements in the indexed array. * * @see CommandPersistence#read() */ private static final int INDEX_PARAMETER_TYPE_DEFINITIONS = 2; /** * Reads all of the category definitions from the commands extension point. * * @param configurationElements * The configuration elements in the commands extension point; * must not be <code>null</code>, but may be empty. * @param configurationElementCount * The number of configuration elements that are really in the * array. * @param commandService * The command service to which the categories should be added; * must not be <code>null</code>. */ private static final void readCategoriesFromRegistry( final IConfigurationElement[] configurationElements, final int configurationElementCount, final ICommandService commandService) { // Undefine all the previous handle objects. final HandleObject[] handleObjects = commandService .getDefinedCategories(); if (handleObjects != null) { for (int i = 0; i < handleObjects.length; i++) { handleObjects[i].undefine(); } } // Define the uncategorized category. commandService .defineUncategorizedCategory( WorkbenchMessages.get().CommandService_AutogeneratedCategoryName, WorkbenchMessages.get().CommandService_AutogeneratedCategoryDescription); final List warningsToLog = new ArrayList(1); for (int i = 0; i < configurationElementCount; i++) { final IConfigurationElement configurationElement = configurationElements[i]; // Read out the category identifier. final String categoryId = readRequired(configurationElement, ATT_ID, warningsToLog, "Categories need an id"); //$NON-NLS-1$ if (categoryId == null) { continue; } // Read out the name. final String name = readRequired(configurationElement, ATT_NAME, warningsToLog, "Categories need a name", //$NON-NLS-1$ categoryId); if (name == null) { continue; } // Read out the description. final String description = readOptional(configurationElement, ATT_DESCRIPTION); final Category category = commandService.getCategory(categoryId); category.define(name, description); } // If there were any warnings, then log them now. logWarnings( warningsToLog, "Warnings while parsing the commands from the 'org.eclipse.ui.commands' and 'org.eclipse.ui.actionDefinitions' extension points."); //$NON-NLS-1$ } /** * Reads all of the command definitions from the commands extension point. * * @param configurationElements * The configuration elements in the commands extension point; * must not be <code>null</code>, but may be empty. * @param configurationElementCount * The number of configuration elements that are really in the * array. * @param commandService * The command service to which the commands should be added; * must not be <code>null</code>. */ private static final void readCommandsFromRegistry( final IConfigurationElement[] configurationElements, final int configurationElementCount, final ICommandService commandService) { // Undefine all the previous handle objects. final HandleObject[] handleObjects = commandService .getDefinedCommands(); if (handleObjects != null) { for (int i = 0; i < handleObjects.length; i++) { handleObjects[i].undefine(); } } final List warningsToLog = new ArrayList(1); for (int i = 0; i < configurationElementCount; i++) { final IConfigurationElement configurationElement = configurationElements[i]; // Read out the command identifier. final String commandId = readRequired(configurationElement, ATT_ID, warningsToLog, "Commands need an id"); //$NON-NLS-1$ if (commandId == null) { continue; } // Read out the name. final String name = readRequired(configurationElement, ATT_NAME, warningsToLog, "Commands need a name"); //$NON-NLS-1$ if (name == null) { continue; } // Read out the description. final String description = readOptional(configurationElement, ATT_DESCRIPTION); // Read out the category id. String categoryId = configurationElement .getAttribute(ATT_CATEGORY_ID); if ((categoryId == null) || (categoryId.length() == 0)) { categoryId = configurationElement.getAttribute(ATT_CATEGORY); if ((categoryId != null) && (categoryId.length() == 0)) { categoryId = null; } } // Read out the parameters. final Parameter[] parameters = readParameters(configurationElement, warningsToLog, commandService); // Read out the returnTypeId. final String returnTypeId = readOptional(configurationElement, ATT_RETURN_TYPE_ID); // Read out the help context identifier. final String helpContextId = readOptional(configurationElement, ATT_HELP_CONTEXT_ID); final Command command = commandService.getCommand(commandId); final Category category = commandService.getCategory(categoryId); if (!category.isDefined()) { addWarning( warningsToLog, "Commands should really have a category", //$NON-NLS-1$ configurationElement, commandId, "categoryId", categoryId); //$NON-NLS-1$ } final ParameterType returnType; if (returnTypeId == null) { returnType = null; } else { returnType = commandService.getParameterType(returnTypeId); } command.define(name, description, category, parameters, returnType, helpContextId); readState(configurationElement, warningsToLog, command); } // If there were any warnings, then log them now. logWarnings( warningsToLog, "Warnings while parsing the commands from the 'org.eclipse.ui.commands' and 'org.eclipse.ui.actionDefinitions' extension points."); //$NON-NLS-1$ } /** * Reads the parameters from a parent configuration element. This is used to * read the parameter sub-elements from a command element. Each parameter is * guaranteed to be valid. If invalid parameters are found, then a warning * status will be appended to the <code>warningsToLog</code> list. * * @param configurationElement * The configuration element from which the parameters should be * read; must not be <code>null</code>. * @param warningsToLog * The list of warnings found during parsing. Warnings found * while parsing the parameters will be appended to this list. * This value must not be <code>null</code>. * @param commandService * The command service from which the parameter can get parameter * types; must not be <code>null</code>. * @return The array of parameters found for this configuration element; * <code>null</code> if none can be found. */ private static final Parameter[] readParameters( final IConfigurationElement configurationElement, final List warningsToLog, final ICommandService commandService) { final IConfigurationElement[] parameterElements = configurationElement .getChildren(TAG_COMMAND_PARAMETER); if ((parameterElements == null) || (parameterElements.length == 0)) { return null; } int insertionIndex = 0; Parameter[] parameters = new Parameter[parameterElements.length]; for (int i = 0; i < parameterElements.length; i++) { final IConfigurationElement parameterElement = parameterElements[i]; // Read out the id final String id = readRequired(parameterElement, ATT_ID, warningsToLog, "Parameters need an id"); //$NON-NLS-1$ if (id == null) { continue; } // Read out the name. final String name = readRequired(parameterElement, ATT_NAME, warningsToLog, "Parameters need a name"); //$NON-NLS-1$ if (name == null) { continue; } /* * The IParameterValues will be initialized lazily as an * IExecutableExtension. */ // Read out the typeId attribute, if present. final String typeId = readOptional(parameterElement, ATT_TYPE_ID); // Read out the optional attribute, if present. final boolean optional = readBoolean(parameterElement, ATT_OPTIONAL, true); final ParameterType type; if (typeId == null) { type = null; } else { type = commandService.getParameterType(typeId); } final Parameter parameter = new Parameter(id, name, parameterElement, type, optional); parameters[insertionIndex++] = parameter; } if (insertionIndex != parameters.length) { final Parameter[] compactedParameters = new Parameter[insertionIndex]; System.arraycopy(parameters, 0, compactedParameters, 0, insertionIndex); parameters = compactedParameters; } return parameters; } /** * Reads all of the commandParameterType definitions from the commands * extension point. * * @param configurationElements * The configuration elements in the commands extension point; * must not be <code>null</code>, but may be empty. * @param configurationElementCount * The number of configuration elements that are really in the * array. * @param commandService * The command service to which the commands should be added; * must not be <code>null</code>. */ private static final void readParameterTypesFromRegistry( final IConfigurationElement[] configurationElements, final int configurationElementCount, final ICommandService commandService) { // Undefine all the previous handle objects. final HandleObject[] handleObjects = commandService .getDefinedParameterTypes(); if (handleObjects != null) { for (int i = 0; i < handleObjects.length; i++) { handleObjects[i].undefine(); } } final List warningsToLog = new ArrayList(1); for (int i = 0; i < configurationElementCount; i++) { final IConfigurationElement configurationElement = configurationElements[i]; // Read out the commandParameterType identifier. final String parameterTypeId = readRequired(configurationElement, ATT_ID, warningsToLog, "Command parameter types need an id"); //$NON-NLS-1$ if (parameterTypeId == null) { continue; } // Read out the type. final String type = readOptional(configurationElement, ATT_TYPE); // Read out the converter. final String converter = readOptional(configurationElement, ATT_CONVERTER); /* * if the converter attribute was given, create a proxy * AbstractParameterValueConverter for the ParameterType, otherwise * null indicates there is no converter */ final AbstractParameterValueConverter parameterValueConverter = (converter == null) ? null : new ParameterValueConverterProxy(configurationElement); final ParameterType parameterType = commandService .getParameterType(parameterTypeId); parameterType.define(type, parameterValueConverter); } // If there were any warnings, then log them now. logWarnings( warningsToLog, "Warnings while parsing the commandParameterTypes from the 'org.eclipse.ui.commands' extension point."); //$NON-NLS-1$ } /** * Reads the states from a parent configuration element. This is used to * read the state sub-elements from a command element. Each state is * guaranteed to be valid. If invalid states are found, then a warning * status will be appended to the <code>warningsToLog</code> list. * * @param configurationElement * The configuration element from which the states should be * read; must not be <code>null</code>. * @param warningsToLog * The list of warnings found during parsing. Warnings found * while parsing the parameters will be appended to this list. * This value must not be <code>null</code>. * @param command * The command for which the state is being read; may be * <code>null</code>. */ private static final void readState( final IConfigurationElement configurationElement, final List warningsToLog, final Command command) { final IConfigurationElement[] stateElements = configurationElement .getChildren(TAG_STATE); if ((stateElements == null) || (stateElements.length == 0)) { return; } for (int i = 0; i < stateElements.length; i++) { final IConfigurationElement stateElement = stateElements[i]; final String id = readRequired(stateElement, ATT_ID, warningsToLog, "State needs an id"); //$NON-NLS-1$ if (id == null) { continue; } if (checkClass(stateElement, warningsToLog, "State must have an associated class", id)) { //$NON-NLS-1$ final State state = new CommandStateProxy(stateElement, ATT_CLASS, PrefUtil.getInternalPreferenceStore(), CommandService.createPreferenceKey(command, id)); command.addState(id, state); } } } /** * The command service with which this persistence class is associated; * never <code>null</code>. */ private final ICommandService commandService; /** * Constructs a new instance of <code>CommandPersistence</code>. * * @param commandService * The command service which should be populated with the values * from the registry; must not be <code>null</code>. */ CommandPersistence(final ICommandService commandService) { if (commandService == null) { throw new NullPointerException("The command service cannot be null"); //$NON-NLS-1$ } this.commandService = commandService; } protected final boolean isChangeImportant(final IRegistryChangeEvent event) { return false; } public boolean commandsNeedUpdating(final IRegistryChangeEvent event) { // RAP [bm]: // final IExtensionDelta[] commandDeltas = event.getExtensionDeltas( // PlatformUI.PLUGIN_ID, IWorkbenchRegistryConstants.PL_COMMANDS); final IExtensionDelta[] commandDeltas = event.getExtensionDeltas( PlatformUI.PLUGIN_EXTENSION_NAME_SPACE, IWorkbenchRegistryConstants.PL_COMMANDS); // RAPEND: [bm] if (commandDeltas.length == 0) { // RAP [bm]: // final IExtensionDelta[] actionDefinitionDeltas = event // .getExtensionDeltas(PlatformUI.PLUGIN_ID, // IWorkbenchRegistryConstants.PL_ACTION_DEFINITIONS); final IExtensionDelta[] actionDefinitionDeltas = event .getExtensionDeltas(PlatformUI.PLUGIN_EXTENSION_NAME_SPACE, IWorkbenchRegistryConstants.PL_ACTION_DEFINITIONS); // RAPEND: [bm] if (actionDefinitionDeltas.length == 0) { return false; } } return true; } /** * Reads all of the commands and categories from the registry, * * @param commandService * The command service which should be populated with the values * from the registry; must not be <code>null</code>. */ protected final void read() { super.read(); reRead(); } public void reRead() { // Create the extension registry mementos. final IExtensionRegistry registry = Platform.getExtensionRegistry(); int commandDefinitionCount = 0; int categoryDefinitionCount = 0; int parameterTypeDefinitionCount = 0; final IConfigurationElement[][] indexedConfigurationElements = new IConfigurationElement[3][]; // Sort the commands extension point based on element name. final IConfigurationElement[] commandsExtensionPoint = registry .getConfigurationElementsFor(EXTENSION_COMMANDS); for (int i = 0; i < commandsExtensionPoint.length; i++) { final IConfigurationElement configurationElement = commandsExtensionPoint[i]; final String name = configurationElement.getName(); // Check if it is a binding definition. if (TAG_COMMAND.equals(name)) { addElementToIndexedArray(configurationElement, indexedConfigurationElements, INDEX_COMMAND_DEFINITIONS, commandDefinitionCount++); } else if (TAG_CATEGORY.equals(name)) { addElementToIndexedArray(configurationElement, indexedConfigurationElements, INDEX_CATEGORY_DEFINITIONS, categoryDefinitionCount++); } else if (TAG_COMMAND_PARAMETER_TYPE.equals(name)) { addElementToIndexedArray(configurationElement, indexedConfigurationElements, INDEX_PARAMETER_TYPE_DEFINITIONS, parameterTypeDefinitionCount++); } } final IConfigurationElement[] actionDefinitionsExtensionPoint = registry .getConfigurationElementsFor(EXTENSION_ACTION_DEFINITIONS); for (int i = 0; i < actionDefinitionsExtensionPoint.length; i++) { final IConfigurationElement configurationElement = actionDefinitionsExtensionPoint[i]; final String name = configurationElement.getName(); if (TAG_ACTION_DEFINITION.equals(name)) { addElementToIndexedArray(configurationElement, indexedConfigurationElements, INDEX_COMMAND_DEFINITIONS, commandDefinitionCount++); } } readCategoriesFromRegistry( indexedConfigurationElements[INDEX_CATEGORY_DEFINITIONS], categoryDefinitionCount, commandService); readCommandsFromRegistry( indexedConfigurationElements[INDEX_COMMAND_DEFINITIONS], commandDefinitionCount, commandService); readParameterTypesFromRegistry( indexedConfigurationElements[INDEX_PARAMETER_TYPE_DEFINITIONS], parameterTypeDefinitionCount, commandService); } }